package com.xique.common.datascope.aspect;

import com.xique.common.core.constant.Constants;
import com.xique.common.datascope.annotation.NeedSetValue;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;

/**
 * 公共的调用方法
 *
 * 用于-切面加注解联表查询
 * @author xl.liu
 *
 */
@Component
public class SetFieldValueUtil implements ApplicationContextAware {

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private CacheManager cacheManager;

    private Cache fieldValueCache;

    @PostConstruct
    public void init()
    {
    	fieldValueCache = cacheManager.getCache(Constants.SYS_FIELD_VALUE_KEY);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (this.applicationContext == null ) {
            this.applicationContext = applicationContext;
        }
    }

    //集合赋值
    public void setValue(Collection col) throws Exception {
        Class<?> clazz = col.iterator().next().getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            NeedSetValue sv = field.getAnnotation(NeedSetValue.class);
            if (sv == null) {
                continue;
            }
            field.setAccessible(true);
            Object bean = this.applicationContext.getBean(sv.beanClass());
            Method method = sv.beanClass().getMethod(sv.method(),clazz.getDeclaredField(sv.params()).getType());
            Field paramField = clazz.getDeclaredField(sv.params());
            paramField.setAccessible(true);
            Field targetField = null;
            boolean needInnerField = !StringUtils.isEmpty(sv.targetFiled());
            //Map<String, Object> cache = new HashMap<>();
            String keyPrefix = sv.beanClass() + "-" + sv.method() + "-" + sv.targetFiled();
            for (Object obj : col) {
                Object paramValue = paramField.get(obj);
                if (paramValue == null) {
                    continue;
                }
                Object value = null;
                // 先从缓存中拿
                String key = keyPrefix + paramValue;
                if (null != fieldValueCache.get(key)) {
                    value = fieldValueCache.get(key);
                    if (value instanceof SimpleValueWrapper) {
                        value = ((SimpleValueWrapper) value).get();
                    }
                } else {
                    value = method.invoke(bean,paramValue);
                    if (needInnerField) {
                        if (value != null) {
                            if (targetField == null) {
                                targetField = value.getClass().getDeclaredField(sv.targetFiled());
                                targetField.setAccessible(true);
                            }
                            value = targetField.get(value);
                        }

                    }
                    fieldValueCache.put(key,value);
                }
                field.set(obj, value);
            }
        }
    }

    //单个实体赋值
    public void setValue(Object obj) throws Exception{
    	 Class<?> clazz = obj.getClass();
         Field[] fields = clazz.getDeclaredFields();
         for (Field field : fields) {
             NeedSetValue sv = field.getAnnotation(NeedSetValue.class);
             if (sv == null) {
                 continue;
             }
             field.setAccessible(true);
             Object bean = this.applicationContext.getBean(sv.beanClass());
             Method method = sv.beanClass().getMethod(sv.method(),clazz.getDeclaredField(sv.params()).getType());
             Field paramField = clazz.getDeclaredField(sv.params());
             paramField.setAccessible(true);
             Field targetField = null;
             boolean needInnerField = !StringUtils.isEmpty(sv.targetFiled());
             //Map<String, Object> cache = new HashMap<>();
             String keyPrefix = sv.beanClass() + "-" + sv.method() + "-" + sv.targetFiled();
                 Object paramValue = paramField.get(obj);
                 if (paramValue == null) {
                     continue;
                 }
                 Object value = null;
                 // 先从缓存中拿
                 String key = keyPrefix + paramValue;
                 if (null != fieldValueCache.get(key)) {
                     value = fieldValueCache.get(key);
                     if (value instanceof SimpleValueWrapper) {
                         value = ((SimpleValueWrapper) value).get();
                     }
                 } else {
                     value = method.invoke(bean,paramValue);
                     if (needInnerField) {
                         if (value != null) {
                             if (targetField == null) {
                                 targetField = value.getClass().getDeclaredField(sv.targetFiled());
                                 targetField.setAccessible(true);
                             }
                             value = targetField.get(value);
                         }

                     }
                     fieldValueCache.put(key,value);
                 }
                 field.set(obj, value);
         }
    }

    //单个实体赋值
    public void setValue2(String key,String value) throws Exception{
        fieldValueCache.put(key,value);
    }
}

